


import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Scanner;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;


// An Acceptor object represents a task that can be executed in a separate
// thread, so it implements the Runnable interface.  Threads begin by calling
// the run() method on some object that implements Runnable; they continue
// executing until the run() method returns (or terminates with an exception).

public class Acceptor extends JFrame implements Runnable
{
	private String name;
	private String description;
	private int listenPort;
	
	private Thread acceptorThread;
	
	private ArrayList<AcceptorListener> listeners;
	
	private ServerSocket serverSocket;
	private Socket socket;
	
	private JLabel drawPicture;
	public byte[] fileBytes;
	
	public Scanner socketIn;
	public PrintWriter socketOut;
	
	public int imageSize;
	public String clientAddress;
	
	
	 
	
	
	public Acceptor(String name, int listenPort)
	{
		this.name = name;
		this.listenPort = listenPort;
		
		listeners = new ArrayList<AcceptorListener>();

		// We create the acceptor thread here but do not start it yet.  This
		// allows the GUI (or whoever) to register itself as a listener before
		// we start waiting for a connection.
		acceptorThread = new Thread(this);

		// Once we accept our conversation, either or both of these will be
		// non-null; initially, though, there are no sockets.
		description = "";
		serverSocket = null;
		socket = null;
		
	}

	
	public void addAcceptorListener(AcceptorListener listener)
	{
		listeners.add(listener);
	}
	
	
	public void removeAcceptorListener(AcceptorListener listener)
	{
		listeners.remove(listener);
	}
	


	public void start()
	{
		acceptorThread.start();
	}
		

	
	public void run()
	{
		clientAddress = null;
		
		try
		{
			// The following is the protocol between client and server.
			serverSocket = new ServerSocket(listenPort);
			socket = serverSocket.accept();
			
			
			
			socketIn = new Scanner(socket.getInputStream());
			socketOut = new PrintWriter(socket.getOutputStream(), true);
		
			clientAddress = socket.getInetAddress().toString();
			
			fireAcceptorSucceeded(clientAddress, "blah");
			
			String line = socketIn.nextLine();
			
			if (!line.startsWith("I45PFP_HELLO"))
			{
				throw new ProtocolException("I45PFP_HELLO expected");
			}
			
			
			
			socketOut.println("GOAHEAD");
			
			
			line = socketIn.nextLine();
			Scanner scanLine = new Scanner(line);
			
			if (!line.startsWith("IMAGE"))
			{
				throw new ProtocolException("IMAGE expected");
			}
			
			
			String imageWord = scanLine.next();
			imageSize = scanLine.nextInt();
			description = scanLine.nextLine();
			 
					
			 		
			firePictureQuery();
			
			
		 			
			
			
			 

			
					
		}
		catch (Exception e)
		{
			fireAcceptorFailed(clientAddress, e);
		}
	
	}



	public void close()
	{
		if (socket != null)
		{
			try
			{
				socket.close();
			}
			catch (IOException e)
			{
			}
		}
		
		if (serverSocket != null)
		{
			try
			{
				serverSocket.close();
			}
			catch (IOException e)
			{
			}
		}
	}
	
	
	public void acceptImage()
	{
		try
		{
			socketOut.println("ACCEPT");
			
			fileBytes = new byte[imageSize];
			
			System.out.println("Image Size is "  + imageSize);
			
			int offset = 0;
			
			
			while (offset < imageSize)
			{
				
				int chunkSize = Math.min(imageSize - offset, 1024);
				offset += socket.getInputStream().read(fileBytes, offset, chunkSize);
				System.out.println(offset + " bytes read");
				
			}
			
			
			firePictureAcceptor(fileBytes, description);
			
			
			
		}
		catch (Exception e)
		{
			fireAcceptorFailed(clientAddress, e);
		}
		finally
		{
			socketOut.println("GOODBYE");
			//close();
			ChatDevice chat = new ChatDevice(socket, listeners.get(0));
			chat.start();
			
			fireCompleted();
		}
		
	}
	
			
	
	public void rejectImage()
	{
		try
		{
		socketOut.println("REJECT");
		}
		catch (Exception e)
		{
			fireAcceptorFailed(clientAddress, e);
		}
		finally
		{
			socketOut.println("GOODBYE");
			//close();
			fireCompleted();
		}
	}
	
	// the following allows the acceptor class to interact with the GUI frame
	
	public void fireAcceptorSucceeded(String clientAddress, String clientName)
	{
		for (AcceptorListener listener : listeners)
		{
			listener.acceptorSucceeded(clientAddress, clientName);
		}
	}
	
	
	public void fireAcceptorFailed(String clientAddress, Exception reason)
	{
		for (AcceptorListener listener : listeners)
		{
			listener.acceptorFailed(clientAddress, reason);
		}
	}
	
	public void firePictureAcceptor(byte[] bytes, String description)
	{
		for (AcceptorListener listener : listeners)
		{
			listener.pictureAccepted(bytes, description);
		}
		
	}
	
	
	public void firePictureQuery()
	{
		for (AcceptorListener listener : listeners)
		{
			listener.pictureQuery();
		}
	}
	
	public void fireCompleted()
	{
		for (AcceptorListener listener : listeners)
		{
			listener.completedServer();
		}
	}
	
	public void fireChat(String text)
	{
		for (AcceptorListener listener : listeners)
		{
			listener.getText(text);
		}
	}
	
}
